package com.tn.service.camera.impl;

import com.tn.controller.alarm.common.constants.Constants;
import com.tn.controller.alarm.common.enums.CommonCodeEnum;
import com.tn.controller.alarm.common.enums.EleFenceType;
import com.tn.controller.alarm.common.model.EleFenceDO;
import com.tn.controller.alarm.common.model.PageInput;
import com.tn.controller.alarm.common.model.PageResult;
import com.tn.controller.alarm.common.model.camera.entity.PositionAreaDO;
import com.tn.controller.alarm.common.model.camera.vo.AreaVideoVO;
import com.tn.controller.alarm.common.model.camera.vo.CameraVO;
import com.tn.controller.alarm.common.model.camera.vo.TimeOfTruckVO;
import com.tn.controller.alarm.common.model.camera.vo.TruckTrialCameraVO;
import com.tn.dao.camera.ICameraDao;
import com.tn.exception.DatabaseOperationFailedException;
import com.tn.service.camera.ICameraService;
import com.tn.service.rpm.RpmServeService;
import com.tn.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 摄像头监控service实现类
 *
 * @program: tn_aucy_java
 * @author: yangjiayao
 * @create: 2022/1/7
 */
@Slf4j
@Service
public class CameraServiceImpl implements ICameraService {
    /**
     * 数据访问层
     */
    private ICameraDao cameraDao;

    /**
     * 点位服务
     */
    private RpmServeService rpmServeService;




    /**
     * 环境
     */
    @Value("${spring.profiles.active}")
    private String environment;

    /**
     * 注入
     *
     * @param cameraDao cameraDao
     */
    @Autowired
    public void setCameraDao(ICameraDao cameraDao) {
        this.cameraDao = cameraDao;
    }

    /**
     * 注入
     *
     * @param rpmServeService rpmServeService
     */
    @Autowired
    public void setRpmServeService(RpmServeService rpmServeService) {
        this.rpmServeService = rpmServeService;
    }

    @Override
    public List<PositionAreaDO> queryArea() {
        return cameraDao.queryArea();
    }

    @Override
    @Transactional
    public void addCamera(CameraVO camera) throws DatabaseOperationFailedException {
        if (checkExistsCameraByName(camera.getName()) || checkExistsCameraByKind(camera)) {
            throw new DatabaseOperationFailedException(CommonCodeEnum.EXISTS.getCode(),
                    CommonCodeEnum.EXISTS.getMessage());
        }
        if (checkNotExistsArea(camera.getAreaId())) {
            throw new DatabaseOperationFailedException(CommonCodeEnum.NOT_EXISTS.getCode(),
                    CommonCodeEnum.NOT_EXISTS.getMessage());
        }
        int num = cameraDao.addCamera(camera);
        if (1 != num || null == camera.getId()) {
            log.error("Unexpect return num or id!");
            throw new DatabaseOperationFailedException(CommonCodeEnum.UNKNOWN.getCode(),
                    CommonCodeEnum.UNKNOWN.getMessage());
        }
        addCameraFence(camera);
        rpmServeService.sendCameraAreaList(cameraDao.queryFenceList());
    }

    @Override
    @Transactional
    public void deleteCamera(CameraVO camera) throws DatabaseOperationFailedException {
        cameraDao.deleteCameraFence(camera.getId(), EleFenceType.CAMERA.toString());
        cameraDao.deleteCamera(camera.getId());
        rpmServeService.sendCameraAreaList(cameraDao.queryFenceList());
    }

    @Override
    @Transactional
    public void modifyCamera(CameraVO camera) throws DatabaseOperationFailedException {
        CameraVO cameraData = cameraDao.queryCameraById(camera.getId());
        if (null == cameraData || checkNotExistsArea(camera.getAreaId())) {
            throw new DatabaseOperationFailedException(CommonCodeEnum.NOT_EXISTS.getCode(),
                    CommonCodeEnum.NOT_EXISTS.getMessage());
        }
        if (checkNotValidCamera(camera, cameraData)) {
            throw new DatabaseOperationFailedException(CommonCodeEnum.EXISTS.getCode(),
                    CommonCodeEnum.EXISTS.getMessage());
        }
        String updateTime = DateUtil.dateToString(new Date());
        camera.setUpdateTime(updateTime);
        modifyCameraFence(camera);
        cameraDao.modifyCamera(camera);
        rpmServeService.sendCameraAreaList(cameraDao.queryFenceList());
    }

    @Override
    public PageResult<CameraVO> queryCamera(PageInput<CameraVO> cameraPage) {
        int total = cameraDao.queryCameraCount(cameraPage.getData());
        PageResult<CameraVO> result = new PageResult<>(cameraPage.getCurPage(), cameraPage.getPageSize(), total);
        if (0 < total) {
            result.setData(cameraDao.queryCameraByPage(result.getStartIndex(), cameraPage.getPageSize(),
                    cameraPage.getData()));
        }
        return result;
    }

    @Override
    public List<CameraVO> queryCameraList() {
        return cameraDao.queryCameraList();
    }

    @Override
    public List<AreaVideoVO> queryVideoList() {
        return cameraDao.queryVideoList();
    }

    @Override
    public PageResult<String> queryTruck(PageInput<Object> page) {
        int total = cameraDao.queryTruckCount();
        PageResult<String> result = new PageResult<>(page.getCurPage(), page.getPageSize(), total);
        if (0 < total) {
            result.setData(cameraDao.queryTruckByPage(result.getStartIndex(), page.getPageSize()));
        }
        return result;
    }

    @Override
    public PageResult<TimeOfTruckVO> queryTimeOfTruck(PageInput<Map<String, String>> page) {
        int total = cameraDao.queryTimeListByLicenseCount(page.getData().get("license"));
        PageResult<TimeOfTruckVO> result = new PageResult<>(page.getCurPage(), page.getPageSize(), total);
        if (0 < total) {
            result.setData(cameraDao.queryTimeListByLicenseByPage(result.getStartIndex(), page.getPageSize(),
                    page.getData().get("license")));
        }
        return result;
    }

    @Override
    public PageResult<TruckTrialCameraVO> queryTruckTrialCamera(PageInput<TimeOfTruckVO> page) {
        int total = cameraDao.queryTruckTrialCameraCount(page.getData());
        PageResult<TruckTrialCameraVO> result = new PageResult<>(page.getCurPage(), page.getPageSize(), total);
        if (0 < total) {
            result.setData(cameraDao.queryTruckTrialCameraByPage(result.getStartIndex(), page.getPageSize(),
                    page.getData()));
        }
        return result;
    }

    @Override
    public void addArea(PositionAreaDO positionArea) {
        cameraDao.addArea(positionArea);
    }

    @Override
    public void editArea(PositionAreaDO positionArea) {
        cameraDao.editArea(positionArea);
    }

    @Override
    public void deleteArea(Integer id) {
        cameraDao.deleteArea(id);
    }

    /**
     * 修改摄像头围栏区域
     *
     * @param camera 摄像头信息
     */
    private void modifyCameraFence(CameraVO camera) {
        EleFenceDO fence = new EleFenceDO();
        fence.setPosition(camera.getFencePosition());
        fence.setFacilityId(camera.getId());
        fence.setUpdateTime(camera.getUpdateTime());
        cameraDao.modifyCameraFence(fence);
    }

    /**
     * 添加摄像头围栏
     *
     * @param camera 摄像头信息
     * @throws DatabaseOperationFailedException 数据库异常
     */
    private void addCameraFence(CameraVO camera) throws DatabaseOperationFailedException {
        EleFenceDO fence = new EleFenceDO();
        fence.setPosition(camera.getFencePosition());
        fence.setFacilityId(camera.getId());
        fence.setType(EleFenceType.CAMERA.toString());
        int num = cameraDao.addCameraFence(fence);
        if (1 != num || null == fence.getId()) {
            log.error("Unexpect return num or id!");
            throw new DatabaseOperationFailedException(CommonCodeEnum.UNKNOWN.getCode(),
                    CommonCodeEnum.UNKNOWN.getMessage());
        }
    }

    /**
     * 校验区域是否存在
     *
     * @param areaId 区域ID
     * @return 是否存在
     */
    private boolean checkNotExistsArea(int areaId) {
        return 0 >= cameraDao.checkExistsArea(areaId);
    }

    /**
     * 校验修改内容是否合法
     *
     * @param cameraInput    入参的摄像头信息
     * @param cameraDataBase 数据库中的摄像头信息
     * @return 是否合法
     */
    private boolean checkNotValidCamera(CameraVO cameraInput, CameraVO cameraDataBase) {
        if (StringUtils.isNotBlank(cameraInput.getName()) && !cameraInput.getName().equals(cameraDataBase.getName())
                && checkExistsCameraByName(cameraInput.getName())) {
            return true;
        }
        return checkNotValidCameraByKind(cameraInput, cameraDataBase);
    }

    /**
     * 校验修改的摄像头类型是否合法
     *
     * @param cameraInput    入参的摄像头信息
     * @param cameraDataBase 数据库中的摄像头信息
     * @return 是否合法
     */
    private boolean checkNotValidCameraByKind(CameraVO cameraInput, CameraVO cameraDataBase) {
        if (StringUtils.isNotBlank(cameraDataBase.getCode())
                && cameraDataBase.getCode().equals(cameraInput.getCode())) {
            return false;
        }
        if (StringUtils.isNotBlank(cameraDataBase.getIp())
                && cameraDataBase.getIp().equals(cameraInput.getIp())) {
            return false;
        }
        return checkExistsCameraByKind(cameraInput);
    }

    /**
     * 校验摄像头名称是否已存在
     *
     * @param name 名称
     * @return 是否存在
     */
    private boolean checkExistsCameraByName(String name) {
        return 0 < cameraDao.checkExistsCameraByName(name);
    }

    /**
     * 校验摄像头是否存在
     *
     * @param camera 摄像头信息
     * @return 是否存在
     */
    private boolean checkExistsCameraByKind(CameraVO camera) {
        if (Constants.TEST_ENVIRONMENT.equals(environment)) {
            return false;
        }
        int result;
        if (Constants.CODE_TYPE_CAMERA == camera.getKind()) {
            result = cameraDao.checkExistsCameraByCode(camera.getCode());
        } else {
            result = cameraDao.checkExistsCameraByIp(camera.getIp());
        }
        return 0 < result;
    }
}
